6. 쿠버네티스 개요5
3.6 서비스 공개
3.6.1 서비스를 사용해서 파드에 접속하기
서비스(Service)란?
쿠버네티스 클러스터에서 실행한 애플리케이션에 네트워크를 통해 접속할 때 필요한 기능이 서비스. 서비스를 사용하면 특정 서비스를 제공하는 여러 파드에 공통 IP 주소를 부여해서 마치 하나의 서비스처럼 접속할 수 있음
서비스가 필요한 이유:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[문제 상황]
파드 IP는 자주 변경됨
│
├─ 스케일링 시 새 파드 생성 → 새 IP 할당
├─ 장애로 파드 재시작 → 새 IP 할당
└─ 롤링 업데이트 → 새 IP 할당
클라이언트가 파드 IP를 직접 알기 어려움
[해결책: Service]
고정 IP + DNS 이름 제공
│
├─ 서비스에 고정 ClusterIP 할당
├─ 서비스명으로 DNS 조회 가능
└─ 로드밸런싱 자동 처리
쿠버네티스는 파드 자체에도 IP 주소가 부여되므로 서비스가 없어도 파드에서 다른 파드에 접근할 수 있음. 하지만 파드의 주소가 자주 바뀔 수 있기 때문에 서비스가 필요함
- 서비스(Service): 여러 파드를 하나의 고정 IP와 DNS 이름으로 묶어 접근할 수 있게 해주는 쿠버네티스 리소스. 파드 IP가 변경되어도 서비스를 통해 안정적으로 접근 가능
- ClusterIP: 서비스에 할당되는 클러스터 내부 전용 가상 IP 주소. 외부에서는 접근 불가
- 로드밸런싱: 트래픽을 여러 파드에 분산하여 부하를 나누는 기능. 서비스가 자동으로 처리함
- CoreDNS: 쿠버네티스 클러스터의 DNS 서버. 서비스명을 ClusterIP로 변환해줌
서비스의 특징:
서비스 동작 방식:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[클라이언트]
│
│ nginx-service:8080 요청
↓
[Service: nginx-service]
ClusterIP: 10.96.100.50
Port: 8080
│
│ selector: app=nginx
│ 로드밸런싱
↓
┌───────────────────────────────┐
│ [Pod1] [Pod2] [Pod3] │
│ app:nginx app:nginx app:nginx
│ :80 :80 :80 │
└───────────────────────────────┘
서비스의 또 다른 특징으로는 접속할 때 이름을 사용할 수 있다는 것이 있음. 서비스를 작성하면 쿠버네티스 클러스터 내부 DNS와 각 파드의 /etc/resolv.conf에도 설정이 적용되기 때문에, 클러스터 내부라면 서비스에 접속할 때 IP 주소 대신에 서비스명으로 접근할 수 있음
서비스 예제:
파일명: nginx-service.yaml
apiVersion: v1 # Kubernetes 코어 API 버전
kind: Service # 리소스 타입 - Service (네트워크 추상화)
metadata:
name: nginx-service # 서비스 이름 (DNS 이름으로도 사용됨)
spec:
selector:
app: nginx # app=nginx 레이블이 있는 파드를 서비스 대상으로 지정
ports:
- protocol: TCP # 프로토콜 (TCP/UDP)
port: 8080 # 서비스가 대기하는 포트 (클라이언트가 접속하는 포트)
targetPort: 80 # 파드가 대기하는 포트 (실제 컨테이너 포트)
파일명: nginx-deployment-3.yaml
apiVersion: apps/v1 # Kubernetes apps API 버전
kind: Deployment # 리소스 타입 - Deployment
metadata:
name: nginx-deployment # 디플로이먼트 이름
spec:
replicas: 3 # 파드 3개 실행
selector:
matchLabels:
app: nginx # 관리할 파드 선택 조건
template:
metadata:
labels:
app: nginx # 파드에 부여할 레이블 (서비스의 selector와 일치)
spec:
containers:
- name: nginx # 컨테이너 이름
image: nginx:1.28 # nginx 이미지 (stable 버전)
ports:
- containerPort: 80 # 컨테이너가 노출하는 포트
서비스 배포 및 테스트:
# 디플로이먼트 배포 (파드 3개 생성)
kubectl apply -f nginx-deployment-3.yaml
# 서비스 배포
kubectl apply -f nginx-service.yaml
# 서비스 상태 확인
# CLUSTER-IP: 클러스터 내부에서 접근 가능한 가상 IP
# PORT(S): 서비스포트:타겟포트
kubectl get service nginx-service
# 서비스 상세 정보 확인 (Endpoints에서 연결된 파드 IP 확인 가능)
kubectl describe service nginx-service
# 서비스명으로 접근 테스트
# kubectl run: 임시 파드 생성
# --rm: 명령 완료 후 파드 삭제
# -it: 인터랙티브 터미널 모드
# --restart=Never: 파드를 한 번만 실행
# wget -qO -: 결과를 표준출력으로 출력 (-q: 조용히, -O -: stdout으로)
# nginx-service:8080: 서비스명과 서비스포트로 접근
kubectl run --rm -it svc-client --image=alpine:3.18 --restart=Never -- wget -qO - http://nginx-service:8080
kubectl get service 명령어로 작성 상태를 확인하면 nginx-service 서비스가 작성되었고, 클러스터 내부에서 접속 가능한 IP 주소가 할당된 것을 확인할 수 있음
헤드리스 서비스:
헤드리스 서비스라는 자체 IP 주소나 로드밸런싱 기능이 없는 서비스를 작성할 수도 있음. 헤드리스 서비스는 서비스를 구성하는 각 파드명을 클러스터 내부 DNS에서 각자 해석할 수 있는 기능이 있음 (스테이트풀셋과 함께 사용)
- 헤드리스 서비스(Headless Service): ClusterIP가 None인 서비스. 로드밸런싱 없이 각 파드에 직접 접근할 수 있으며, StatefulSet과 함께 사용하여 개별 파드를 DNS로 식별
- Endpoints: 서비스가 트래픽을 전달할 실제 파드 IP 목록. 서비스의 selector와 일치하는 파드들이 자동으로 등록됨
클러스터 내부에서 서비스 접근 테스트
서비스를 생성하면 클러스터 내부에서 다양한 방식으로 접근할 수 있음. 외부에서 접근하기 전에 내부에서 서비스가 제대로 동작하는지 확인하는 것이 중요함
내부 접근 방식:
클러스터 내부 접근 방법:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[방법 1: 서비스명 (DNS)]
http://nginx-service:8080
│
└─ CoreDNS가 서비스명을 ClusterIP로 변환
가장 권장되는 방식
[방법 2: ClusterIP 직접]
http://10.96.100.50:8080
│
└─ kubectl get service로 확인한 IP 사용
IP가 변경될 수 있으므로 테스트용
[방법 3: 전체 DNS 이름]
http://nginx-service.default.svc.cluster.local:8080
│
└─ 다른 네임스페이스에서 접근 시 사용
<서비스명>.<네임스페이스>.svc.cluster.local
내부 접근 테스트 방법:
# 방법 1: 임시 파드에서 테스트 (권장)
kubectl run test-client --rm -it --image=curlimages/curl --restart=Never -- http://nginx-service:8080
# 방법 2: 기존 파드에서 테스트
kubectl exec -it <pod-name> -- curl http://nginx-service:8080
# 방법 3: ClusterIP로 직접 테스트
kubectl exec -it <pod-name> -- curl http://10.96.100.50:8080
# 방법 4: busybox로 테스트
kubectl run test --rm -it --image=busybox --restart=Never -- wget -qO- http://nginx-service:8080
DNS 확인:
# 서비스 DNS 조회
kubectl run dns-test --rm -it --image=busybox --restart=Never -- nslookup nginx-service
# 출력 예시:
# Server: 10.96.0.10
# Address: 10.96.0.10:53
# Name: nginx-service.default.svc.cluster.local
# Address: 10.96.100.50
3.6.2 외부에 서비스 공개하기
서비스 기능을 사용해서 어떤 서비스를 구성하는 파드 그룹을 하나로 묶어서 공통 IP 주소를 부여할 수 있지만, 이렇게 작성한 서비스는 클러스터 IP(ClusterIP)이기 때문에 서비스에 부여된 IP 주소는 쿠버네티스 내부에서만 유효하고 인터넷 같은 클러스터 외부에서는 접근할 수 없음
서비스 타입 계층 구조:
서비스 타입은 상위 타입이 하위 타입의 기능을 모두 포함하는 계층 구조를 가짐
서비스 타입 상속 관계:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ClusterIP (기본)
│
└─ 내부 접근만 가능
- ClusterIP: 10.96.100.50
- DNS: nginx-service
↓ 상속
NodePort = ClusterIP + 노드포트
│
├─ ClusterIP 기능 포함 (내부 접근)
│ - ClusterIP: 10.96.100.50
│ - DNS: nginx-service
│
└─ + 노드포트 추가 (외부 접근)
- <모든노드IP>:30080
↓ 상속
LoadBalancer = NodePort + 외부 LB
│
├─ ClusterIP 기능 포함
├─ NodePort 기능 포함
└─ + 클라우드 로드밸런서 추가
- External IP: 203.0.113.10
하나의 NodePort 서비스에 대한 접근 방식:
예: nginx-nodeport 서비스 (TYPE: NodePort)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
kubectl get service nginx-nodeport
→ CLUSTER-IP: 10.102.184.141, PORT: 80:30080/TCP
[클러스터 내부에서 접근 (3가지 모두 가능)]
│
├─ nginx-nodeport:80 (DNS → ClusterIP)
├─ 10.102.184.141:80 (ClusterIP 직접)
└─ 192.168.65.3:30080 (노드IP + NodePort)
[클러스터 외부에서 접근]
│
├─ localhost:30080 (Docker Desktop 자동 포워딩)
└─ <공인IP>:30080 (실제 노드의 공인IP)
[접근 불가]
│
├─ Windows → 192.168.65.3:30080 ✗ (VM 내부 IP)
└─ Windows → 10.102.184.141:80 ✗ (클러스터 내부 IP)
외부 트래픽 흐름 (NodePort 예시):
외부에서 NodePort로 접근 시 트래픽 흐름:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[외부 클라이언트]
│
│ http://<공인IP>:30080
↓
[Node (공인IP:30080)]
│
│ NodePort가 트래픽 수신
↓
[kube-proxy]
│
│ iptables/IPVS 규칙으로 라우팅
↓
[Service (ClusterIP:80)]
│
│ 로드밸런싱 (라운드로빈)
↓
[Pod 선택]
├─ Pod1:80
├─ Pod2:80
└─ Pod3:80
서비스 타입별 포트 관계:
포트 용어 정리:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[NodePort 서비스 예시]
spec:
type: NodePort
ports:
- port: 80 # 서비스 포트 (ClusterIP에서 사용)
targetPort: 80 # 파드 포트 (컨테이너가 리스닝)
nodePort: 30080 # 노드 포트 (외부 노출)
접근 경로:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
외부 → <노드IP>:30080 (nodePort)
↓
내부 → ClusterIP:80 (port)
↓
파드 → Pod:80 (targetPort)
서비스 타입 비교:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[ClusterIP] (기본값)
├─ 클러스터 내부에서만 접근 가능
└─ 외부 노출 불가
[NodePort]
├─ 각 노드의 고정 포트로 외부 노출
├─ 포트 범위: 30000-32767
└─ 노드 IP:포트로 접근
[LoadBalancer]
├─ 외부 로드밸런서 자동 프로비저닝
├─ 클라우드 환경에서 주로 사용
└─ 로컬 환경에서는 (Bare)MetalLB 필요
[ExternalName]
├─ 외부 DNS 이름을 서비스로 매핑
└─ 클러스터 외부 서비스 참조용
- NodePort: 각 노드의 고정 포트(30000-32767)를 통해 외부에서 접근할 수 있게 하는 서비스 타입. ClusterIP 기능을 포함함
- LoadBalancer: 클라우드 로드밸런서를 자동 프로비저닝하여 외부 IP를 할당받는 서비스 타입. NodePort와 ClusterIP 기능을 포함함
- ExternalName: 외부 도메인을 클러스터 내부 서비스명으로 참조할 수 있게 해주는 서비스 타입
- kube-proxy: 각 노드에서 서비스 트래픽을 적절한 파드로 라우팅하는 컴포넌트. iptables 또는 IPVS 규칙을 관리함
- targetPort: 파드 내 컨테이너가 실제로 리스닝하는 포트
- port: 서비스가 클러스터 내부에서 노출하는 포트 (ClusterIP에서 사용)
- nodePort: 노드 외부에서 접근 시 사용하는 포트 (30000-32767 범위)
외부 접근 방식 다이어그램:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[인터넷/외부 클라이언트]
│
↓
┌─────────────────────────────────────┐
│ [LoadBalancer] │
│ 외부 IP: 203.0.113.10 │
│ :80 │
│ │ │
│ ┌──────────────┼──────────────┐ │
│ │ ↓ │ │
│ │ [NodePort Service] │ │
│ │ 모든 노드의 :30080 │ │
│ │ │ │ │
│ ├──────────────┼──────────────┤ │
│ │ ↓ │ │
│ │ [ClusterIP Service] │ │
│ │ 10.96.100.50:80 │ │
│ │ │ │ │
│ │ ┌─────────┼─────────┐ │ │
│ │ ↓ ↓ ↓ │ │
│ │ [Pod1] [Pod2] [Pod3] │ │
│ │ :80 :80 :80 │ │
│ └─────────────────────────────┘ │
│ Kubernetes Cluster │
└─────────────────────────────────────┘
NodePort 서비스:
NodePort는 서비스의 일종으로, 각 노드의 고정 포트를 클러스터 외부에 공개해서 해당 포트를 통한 통신을, 서비스를 구성하는 파드 중 하나에 로드밸런싱함
NodePort 동작 방식:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[외부 클라이언트]
│
│ http://<노드IP>:30080
↓
┌─────────────────────────────────────┐
│ [Node1:30080] [Node2:30080] [Node3:30080]
│ │ │ │
│ └─────────────┼─────────────┘
│ ↓
│ [Service: NodePort]
│ │
│ ┌─────────────┼─────────────┐
│ ↓ ↓ ↓
│ [Pod1] [Pod2] [Pod3]
│ :80 :80 :80
└─────────────────────────────────────┘
특징:
├─ 어느 노드의 30080 포트로 접근해도 동일 서비스
├─ 포트 범위: 30000-32767
└─ 노드 IP를 직접 알아야 함
파일명: nodeport-service.yaml
apiVersion: v1 # Kubernetes 코어 API 버전
kind: Service # 리소스 타입 - Service
metadata:
name: nginx-nodeport # 서비스 이름
spec:
type: NodePort # 서비스 타입 - NodePort (외부 노출)
selector:
app: nginx # app=nginx 레이블이 있는 파드 대상
ports:
- protocol: TCP # 프로토콜
port: 80 # 클러스터 내부에서 서비스 접근 시 사용하는 포트
targetPort: 80 # 파드가 대기하는 포트
nodePort: 30080 # 노드에서 외부로 노출하는 포트 (30000-32767 범위)
# 생략 시 자동 할당
NodePort 배포 및 테스트:
# NodePort 서비스 배포
kubectl apply -f nodeport-service.yaml
# 서비스 확인
# TYPE: NodePort
# PORT(S): 80:30080/TCP (서비스포트:노드포트)
kubectl get service nginx-nodeport
# 노드 IP 확인
kubectl get nodes -o wide
# 외부에서 접근 테스트 (노드IP:노드포트)
# Windows에서는 localhost 또는 Docker Desktop의 IP 사용
curl http://localhost:30080
# 또는
curl http://<노드-IP>:30080
단, 노드 자체에서 클러스터 외부 공개가 여러 개이거나 또는 노드가 여러 개라면 노드 그룹의 로드밸런서 설정은 사용자가 직접 해야 함
LoadBalancer 서비스:
로드밸런서 서비스도 서비스의 일종. 클라우드 제공 업체처럼 쿠버네티스용 로드밸런서 기능을 제공하는 플랫폼에서 사용할 수 있으며, 로드밸런서를 통해 각 서비스를 클러스터 외부에 공개할 수 있음
LoadBalancer 동작 방식:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[외부 클라이언트]
│
│ http://203.0.113.10:80
↓
[Cloud Load Balancer] ← 클라우드가 자동 프로비저닝
External IP: 203.0.113.10
│
│ 트래픽 분산
↓
┌─────────────────────────────────────┐
│ [Node1] [Node2] [Node3] │
│ │ │ │ │
│ └───────────┼───────────┘ │
│ ↓ │
│ [Service: LoadBalancer] │
│ │ │
│ ┌─────────┼─────────┐ │
│ ↓ ↓ ↓ │
│ [Pod1] [Pod2] [Pod3] │
└─────────────────────────────────────┘
파일명: loadbalancer-service.yaml
apiVersion: v1 # Kubernetes 코어 API 버전
kind: Service # 리소스 타입 - Service
metadata:
name: nginx-loadbalancer # 서비스 이름
spec:
type: LoadBalancer # 서비스 타입 - LoadBalancer (외부 LB 사용)
selector:
app: nginx # app=nginx 레이블이 있는 파드 대상
ports:
- protocol: TCP # 프로토콜
port: 80 # 외부 로드밸런서가 대기하는 포트
targetPort: 80 # 파드가 대기하는 포트
LoadBalancer 배포:
# LoadBalancer 서비스 배포
kubectl apply -f loadbalancer-service.yaml
# 서비스 확인
# EXTERNAL-IP: 외부에서 접근 가능한 IP (할당 시간 소요)
# 클라우드 환경에서는 실제 공인 IP 할당
# 로컬 환경에서는 <pending> 상태 유지 (MetalLB 없는 경우)
kubectl get service nginx-loadbalancer
# 외부 IP 할당 대기 (실시간 확인)
kubectl get service nginx-loadbalancer -w
클러스터 외부에서 보면 로드밸런서가 공개한 IP 주소와 포트에 접속하면 해당 포트를 공개하는 로드밸런서 서비스를 통해서 서비스를 구성하는 파드 중 하나에 통신이 전송됨. GKE, EKS, AKS 등의 플랫폼이 제공하는 로드밸런서 기능을 사용하는 것임
로컬 환경에서 LoadBalancer 사용하기 (MetalLB):
클라우드가 아닌 로컬 환경(Docker Desktop, Minikube, 베어메탈)에서는 LoadBalancer 타입을 사용해도 EXTERNAL-IP가 <pending> 상태로 유지됨. 이때 MetalLB를 설치하면 로컬에서도 LoadBalancer를 사용할 수 있음
# MetalLB 설치 (네임스페이스 및 컴포넌트)
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.14.9/config/manifests/metallb-native.yaml
# MetalLB 파드 준비 대기
kubectl wait --namespace metallb-system --for=condition=ready pod --selector=app=metallb --timeout=90s
MetalLB IP 풀 설정 파일: metallb-config.yaml
apiVersion: metallb.io/v1beta1 # MetalLB API 버전
kind: IPAddressPool # IP 주소 풀 정의
metadata:
name: default-pool # 풀 이름
namespace: metallb-system # MetalLB 네임스페이스
spec:
addresses:
- 192.168.49.100-192.168.49.120 # 할당할 IP 범위 (환경에 맞게 수정)
# Docker Desktop: 172.17.0.100-172.17.0.120
# Minikube: minikube ip 결과 참고
---
apiVersion: metallb.io/v1beta1 # MetalLB API 버전
kind: L2Advertisement # L2 모드 광고 설정
metadata:
name: default # 광고 이름
namespace: metallb-system # MetalLB 네임스페이스
# MetalLB 설정 적용
kubectl apply -f metallb-config.yaml
# 이제 LoadBalancer 서비스에 EXTERNAL-IP 할당됨
kubectl get service nginx-loadbalancer
인그레스 (Ingress):
인그레스는 다수의 서비스 접속을 관리할 수 있는 기능. 예를 들어 하나의 HTTP 기반 애플리케이션을 여러 개의 서비스를 사용해 구성하고, URL 호스트명과 경로 규칙을 기반으로 실제로 접속할 서비스를 매니페스트에 지정할 수 있는 등 로드밸런싱 기능이 포함되어 있음
인그레스 동작 방식:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[외부 요청]
│
├─ http://example.com/api/*
├─ http://example.com/web/*
└─ http://admin.example.com/*
│
↓
[Ingress Controller] ← nginx-ingress, traefik 등
│
│ URL 경로/호스트 기반 라우팅
│
├─ /api/* → [Service: api-service] → [API Pods]
├─ /web/* → [Service: web-service] → [Web Pods]
└─ admin.* → [Service: admin-service] → [Admin Pods]
장점:
├─ 하나의 외부 IP로 여러 서비스 노출
├─ URL 경로 기반 라우팅
├─ 호스트명 기반 라우팅
├─ SSL/TLS 종료 처리
└─ 로드밸런서 비용 절감
쿠버네티스 자체는 인그레스를 관리하는 컴포넌트가 포함되지 않으므로 사용자가 직접 도입하거나 클라우드 제공 업체의 쿠버네티스 운영 플랫폼에서 제공하는 것을 사용해야 함
- 인그레스(Ingress): HTTP/HTTPS 트래픽을 URL 경로나 호스트명 기반으로 여러 서비스로 라우팅하는 API 객체. L7 로드밸런싱 제공
- 인그레스 컨트롤러(Ingress Controller): 인그레스 리소스를 실제로 처리하는 컴포넌트. nginx-ingress, traefik 등 다양한 구현체가 있음
- ingressClassName: 어떤 인그레스 컨트롤러가 해당 인그레스를 처리할지 지정하는 필드
- pathType: URL 경로 매칭 방식. Prefix(접두사 매칭), Exact(정확히 일치), ImplementationSpecific(컨트롤러 구현에 따름)
- SSL/TLS 종료(Termination): HTTPS 암호화를 인그레스 컨트롤러에서 해제하여 내부 서비스에는 HTTP로 전달하는 것
- MetalLB: 베어메탈/로컬 환경에서 LoadBalancer 서비스를 사용할 수 있게 해주는 로드밸런서 구현체
인그레스 컨트롤러는 다양한 구현체가 있음:
- Ingress-NGINX: 가장 널리 사용되는 오픈소스 컨트롤러
- GKE Ingress: Google Kubernetes Engine 기본 제공
- AWS Load Balancer Controller: AWS EKS용
- Traefik: 클라우드 네이티브 프록시
Ingress-NGINX 설치 (로컬/베어메탈 환경):
# Ingress-NGINX 컨트롤러 설치
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.12.0/deploy/static/provider/cloud/deploy.yaml
# 설치 확인
kubectl get pods -n ingress-nginx
# Ingress 컨트롤러 서비스 확인
kubectl get service -n ingress-nginx
인그레스 예제:
파일명: ingress-example.yaml
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 서비스 정의
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
apiVersion: v1 # Kubernetes 코어 API 버전
kind: Service # 리소스 타입 - Service
metadata:
name: nginx-service # 서비스 이름
spec:
selector:
app: nginx # app=nginx 레이블이 있는 파드 대상
ports:
- protocol: TCP # 프로토콜
port: 80 # 서비스 포트
targetPort: 80 # 파드 포트
---
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
# 인그레스 정의
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
apiVersion: networking.k8s.io/v1 # Ingress API 버전 (networking.k8s.io/v1 권장)
kind: Ingress # 리소스 타입 - Ingress
metadata:
name: nginx-ingress # 인그레스 이름
annotations: # 인그레스 컨트롤러별 설정
nginx.ingress.kubernetes.io/rewrite-target: / # URL 재작성 (선택사항)
spec:
ingressClassName: nginx # 사용할 인그레스 컨트롤러 클래스
# Ingress-NGINX 사용 시 "nginx"
rules:
- host: example.local # 호스트명 (생략 시 모든 호스트에 적용)
http:
paths:
- path: / # URL 경로 (루트 경로)
pathType: Prefix # 경로 매칭 방식
# Prefix: /로 시작하는 모든 경로
# Exact: 정확히 일치하는 경로만
# ImplementationSpecific: 컨트롤러 구현에 따름
backend:
service:
name: nginx-service # 트래픽을 전달할 서비스 이름
port:
number: 80 # 서비스 포트
인그레스 배포 및 테스트:
# 디플로이먼트와 인그레스 배포
kubectl apply -f nginx-deployment-3.yaml
kubectl apply -f ingress-example.yaml
# 인그레스 상태 확인
# ADDRESS: 인그레스 컨트롤러의 외부 IP
kubectl get ingress nginx-ingress
# 인그레스 상세 정보
kubectl describe ingress nginx-ingress
# 로컬 테스트 (hosts 파일 수정 또는 Host 헤더 사용)
# Linux/macOS
curl -H "Host: example.local" http://localhost
# Windows PowerShell
curl.exe -H "Host: example.local" http://localhost
# 또는 Invoke-WebRequest
Invoke-WebRequest -Uri "http://localhost" -Headers @{"Host"="example.local"}
다중 경로 인그레스 예제:
파일명: multi-path-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-path-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2 # 캡처 그룹으로 경로 재작성
spec:
ingressClassName: nginx
rules:
- host: myapp.local
http:
paths:
# /api/* 요청은 api-service로 라우팅
- path: /api(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: api-service
port:
number: 8080
# /web/* 요청은 web-service로 라우팅
- path: /web(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: web-service
port:
number: 80
# 기본 경로는 default-service로 라우팅
- path: /
pathType: Prefix
backend:
service:
name: default-service
port:
number: 80
서비스 타입 선택 가이드:
서비스 타입 선택 기준:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[ClusterIP]
사용 시점:
├─ 클러스터 내부 통신만 필요
├─ 마이크로서비스 간 통신
└─ 외부 노출 불필요
[NodePort]
사용 시점:
├─ 개발/테스트 환경
├─ 간단한 외부 노출 필요
└─ 로드밸런서 없는 환경
제한:
├─ 포트 범위 제한 (30000-32767)
└─ 노드 IP 직접 노출
[LoadBalancer]
사용 시점:
├─ 프로덕션 환경
├─ 클라우드 환경 (GKE, EKS, AKS)
└─ 고가용성 필요
로컬 환경:
└─ MetalLB 설치 필요
[Ingress]
사용 시점:
├─ 여러 서비스를 하나의 IP로 노출
├─ URL 경로 기반 라우팅 필요
├─ SSL/TLS 종료 처리
└─ 로드밸런서 비용 절감
필수 조건:
└─ Ingress Controller 설치 필요
리소스 정리:
# 서비스 삭제
kubectl delete service nginx-service nginx-nodeport nginx-loadbalancer
# 인그레스 삭제
kubectl delete ingress nginx-ingress
# 디플로이먼트 삭제
kubectl delete deployment nginx-deployment
# 또는 파일로 삭제
kubectl delete -f nginx-service.yaml
kubectl delete -f nodeport-service.yaml
kubectl delete -f loadbalancer-service.yaml
kubectl delete -f ingress-example.yaml
참고 자료
공식 문서:
- Services: https://kubernetes.io/docs/concepts/services-networking/service/
- Ingress: https://kubernetes.io/docs/concepts/services-networking/ingress/
- Ingress Controllers: https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/
- DNS for Services and Pods: https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/
Ingress Controller:
- NGINX Ingress Controller: https://kubernetes.github.io/ingress-nginx/
- AWS ALB Ingress Controller: https://kubernetes-sigs.github.io/aws-load-balancer-controller/